from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, HttpUrl
from typing import Annotated, Optional
from datetime import timedelta, datetime
import random
import redis
import bcrypt
import logging
import json

# 本地模块导入
from schemas.user_schemas import UserCreate, UserOut, UserLogin, Token
from models.user import MembershipLevel, User
from config.settings import ACCESS_TOKEN_EXPIRE_MINUTES
from tortoise.expressions import Q
from tortoise.exceptions import DoesNotExist
from tasks.sms_tasks import send_sms_task
from utils.generate_verfy_token import create_access_token, verify_token


# 初始化组件
router = APIRouter(prefix='/user', tags=['用户模块'])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="user/login/account")
redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 日志配置
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


# 请求模型定义
class SmsCodeRequest(BaseModel):
    phone: str


class QuickLoginRequest(BaseModel):
    phone: str
    code: str


class UserRegisterSimple(BaseModel):
    username: str
    password: str


class ConsumptionRequest(BaseModel):
    amount: float
    description: str


class CommonQueryParams:
    def __init__(self, username: Optional[str] = None, password: Optional[str] = None):
        self.username = username
        self.password = password


# 接口实现
@router.post('/api/send_sms_code', summary='发送短信验证码')
async def send_sms_code(request: SmsCodeRequest):
    """发送手机验证码（有效期5分钟）"""
    phone = request.phone
    if not (phone.isdigit() and len(phone) == 11):
        return {'success': False, 'message': '无效手机号'}
    
    # 生成验证码并存储到Redis
    code = ''.join([str(random.randint(0, 9)) for _ in range(4)])
    valid_time = 5  # 分钟
    redis_client.setex(f"sms_code:{phone}", valid_time * 60, code)
    logger.info(f"生成验证码: {code}，手机号: {phone}，有效期: {valid_time}分钟")
    
    # 异步发送短信
    send_sms_task.delay(phone, code, valid_time)
    return {'success': True, 'message': '验证码已发送，请注意查收'}


@router.post('/register', response_model=UserOut, summary='用户注册')
async def register_user(user: UserCreate):
    """用户注册接口（默认初始会员等级为"普通"）"""
    # 检查用户是否已存在
    if await User.get_or_none(username=user.username):
        raise HTTPException(status_code=400, detail='用户已存在')
    
    # 获取默认会员等级
    default_membership = await MembershipLevel.get_or_create(
        name="普通",
        defaults={"upgrade_amount": 0.00, "level": 0, "discount": 100}
    )[0]

    # 密码加密并创建用户
    hashed_pwd = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
    user = await User.create(
        username=user.username, 
        phone=user.phone, 
        password=hashed_pwd, 
        email=user.email,
        membership_level=default_membership,
        balance=0.00
    )
    
    if not user:
        raise HTTPException(status_code=400, detail='创建用户失败')
    return user


@router.post('/login/account', response_model=Token, summary='账号密码登录')
async def login(user: UserLogin) -> Token:
    """通过用户名/手机号+密码登录"""
    # 查询用户
    user_query = await User.get_or_none(Q(username=user.username) | Q(phone=user.username))
    if not user_query:
        raise HTTPException(status_code=400, detail='用户不存在')
    
    # 验证密码
    if not user_query.verify_password(user.password):
        raise HTTPException(status_code=400, detail='密码错误')
    
    # 生成token
    access_token = create_access_token(
        data={"sub": user_query.username},
        expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    )
    return Token(access_token=access_token, token_type="bearer")


@router.post('/login/quick', response_model=Token, summary='短信快捷登录')
async def quick_login(request: QuickLoginRequest) -> Token:
    """通过手机号+验证码登录（未注册用户自动创建账号）"""
    phone = request.phone
    code = request.code
    
    # 验证手机号格式
    if not (phone.isdigit() and len(phone) == 11):
        raise HTTPException(status_code=400, detail="手机号必须为11位数字")
    
    # 验证验证码
    stored_code = redis_client.get(f"sms_code:{phone}")
    if not stored_code or stored_code != code:
        raise HTTPException(status_code=400, detail="验证码错误或已过期")
    
    # 查询或创建用户
    user = await User.get_or_none(phone=phone)
    if not user:
        # 自动注册新用户
        default_membership = await MembershipLevel.get_or_create(
            name="普通",
            defaults={"upgrade_amount": 0.00, "level": 0, "discount": 100}
        )[0]
        random_password = str(random.randint(100000, 999999))
        hashed_pwd = bcrypt.hashpw(random_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
        user = await User.create(
            username=phone,
            phone=phone,
            password=hashed_pwd,
            membership_level=default_membership,
            balance=0.00
        )
    
    # 生成token
    access_token = create_access_token(
        data={"sub": user.username},
        expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    )
    return Token(access_token=access_token, token_type="bearer")


@router.put('/update_avatar', summary='更新用户头像')
async def update_avatar(avatar: HttpUrl, request: Request):
    """更新用户头像（仅支持jpg、jpeg、png、gif格式）"""
    username = request.state.username
    if not username:
        raise HTTPException(status_code=401, detail="未授权访问")
    
    user = await User.get_or_none(username=username)
    if not user:
        raise HTTPException(status_code=404, detail='用户不存在')
    
    # 验证图片格式和协议
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif']
    if not any(avatar.path.endswith(ext) for ext in allowed_extensions):
        raise HTTPException(status_code=400, detail="仅支持jpg、jpeg、png、gif格式的图片")
    if avatar.scheme not in ['http', 'https']:
        raise HTTPException(status_code=400, detail="头像URL必须使用http/https协议")
    
    # 更新头像
    try:
        user.avatar = str(avatar)
        await user.save()
        return JSONResponse({
            "success": True,
            "message": "头像更新成功",
            "data": {"avatar": str(avatar)}
        })
    except Exception as e:
        logger.error(f"更新头像失败: {str(e)}")
        raise HTTPException(status_code=500, detail="更新头像失败，请稍后重试")


@router.put('/update_password', summary='修改密码')
async def update_password(old_password: str, new_password: str, request: Request):
    """修改用户密码（需验证旧密码）"""
    username = request.state.username
    if not username:
        raise HTTPException(status_code=401, detail="未授权访问")
    
    user = await User.get_or_none(username=username)
    if not user:
        raise HTTPException(status_code=404, detail='用户不存在')
    
    if not user.verify_password(old_password):
        raise HTTPException(status_code=400, detail='旧密码错误')
    
    user.set_password(new_password)
    await user.save()
    return {'message': '密码更新成功'}


@router.put('/update_phone', summary='修改手机号')
async def update_phone(phone: str, request: Request):
    """修改用户绑定的手机号"""
    username = request.state.username
    if not username:
        raise HTTPException(status_code=401, detail="未授权访问")
    
    user = await User.get_or_none(username=username)
    if not user:
        raise HTTPException(status_code=404, detail='用户不存在')
    
    if not (phone.isdigit() and len(phone) == 11):
        raise HTTPException(status_code=400, detail="无效的手机号格式")
    
    user.phone = phone
    await user.save()
    return {'message': '手机号更新成功'}


@router.get('/membership_info', summary='获取会员等级信息')
async def get_user_membership_info(request: Request):
    try:
        # 验证令牌有效性
        token = request.headers.get("Authorization", "").split(" ")[-1]
        if not token or not await verify_token(token):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="令牌无效或已过期",
                headers={"WWW-Authenticate": "Bearer"}
            )
        
        username = request.state.username
        if not username:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="未授权访问，请先登录",
                headers={"WWW-Authenticate": "Bearer"}
            )
        
        user = await User.get_or_none(username=username).prefetch_related('membership_level')
        if not user:
            raise HTTPException(status_code=404, detail='用户不存在')
        
        # 组装会员等级数据（修正remaining计算逻辑）
        current_membership = user.membership_level or {}
        levels = await MembershipLevel.all().order_by('level')
        levels_info = []
        has_current = False  # 标记是否有当前等级
        
        for level in levels:
            is_current = level.level == (current_membership.level if current_membership else 0)
            if is_current:
                has_current = True
            
            # 修正：剩余金额 = 目标等级所需金额 - 用户当前累计消费
            # 注意：需确保User模型有累计消费字段（此处假设为total_consumed，若无需补充）
            user_total_consumed = float(user.total_consumed) if hasattr(user, 'total_consumed') else 0.0
            remaining = max(0, float(level.upgrade_amount) - user_total_consumed)
            
            levels_info.append({
                "name": level.name,
                "level": level.level,
                "required_amount": float(level.upgrade_amount),
                "is_current": is_current,
                "remaining": remaining
            })
        
        # 确保至少有一个当前等级（兼容数据异常情况）
        if not has_current and levels_info:
            levels_info[0]["is_current"] = True
        
        return JSONResponse({
            "username": user.username,
            "avatar": user.avatar,
            "current_membership": {
                "name": current_membership.name if current_membership else "普通",
                "level": current_membership.level if current_membership else 0,
                # 修正：当前累计消费应为用户实际消费金额（非等级升级金额）
                "total_consumed": user_total_consumed,
                "discount": current_membership.discount if current_membership else 100
            },
            "levels": levels_info,
            "is_current_user": True
        })
    except Exception as e:
        return JSONResponse(
            status_code=400 if isinstance(e, HTTPException) else 500,
            content={"detail": str(e) or "获取会员信息失败"}
        )


@router.get("/user_info", response_model=UserOut)
async def get_user_info(token: str = Depends(oauth2_scheme)):
    try:
        # 验证令牌并获取用户名
        username = await verify_token(token)
        # 查询用户信息（包含会员等级）
        current_user = await User.get(username=username).prefetch_related('membership_level')
        return current_user
    except DoesNotExist:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在或令牌无效",
            headers={"WWW-Authenticate": "Bearer"},
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"授权失败: {str(e)}",
            headers={"WWW-Authenticate": "Bearer"},
        )


@router.post("/logout", summary="退出登录")
async def logout(request: Request):
    """退出登录（将token加入黑名单）"""
    try:
        username = request.state.username
        if not username:
            raise HTTPException(status_code=401, detail="令牌无效")
        
        user = await User.get(username=username)
        now = datetime.now(datetime.timezone.utc).timestamp()
        exp = request.state.exp
        
        if not exp:
            raise HTTPException(status_code=401, detail="令牌格式异常")
        
        # 计算剩余有效期并加入黑名单
        remaining_seconds = max(0, int(exp - now))
        if remaining_seconds <= 0:
            raise HTTPException(status_code=401, detail="令牌已过期")
        
        token = request.headers.get("Authorization").split(" ")[1]
        redis_client.setex(f"blacklist:{token}", remaining_seconds, value="invalid")
        
        logger.info(f"用户 {username} 退出登录成功")
        return {"message": "退出登录成功"}
        
    except DoesNotExist:
        raise HTTPException(status_code=404, detail="用户不存在")
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"退出登录异常: {str(e)}")
        raise HTTPException(status_code=500, detail="服务器处理退出请求失败")


@router.post('/consume_and_upgrade', summary='消费并升级会员')
async def consume_and_upgrade(request: ConsumptionRequest, request_obj: Request):
    """用户消费后更新累计金额并自动升级会员等级"""
    username = request_obj.state.username
    if not username:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="未授权访问，请先登录",
            headers={"WWW-Authenticate": "Bearer"}
        )
    
    user = await User.get_or_none(username=username).prefetch_related('membership_level')
    if not user:
        raise HTTPException(status_code=404, detail='用户不存在')
    
    if request.amount <= 0:
        raise HTTPException(status_code=400, detail='消费金额必须大于0')
    
    # 计算当前等级和累计消费（修正：使用用户实际累计消费字段）
    current_level = user.membership_level.level if user.membership_level else 0
    current_total = float(user.total_consumed) if hasattr(user, 'total_consumed') else 0.0
    new_total = current_total + request.amount
    
    # 更新用户累计消费（需确保User模型有total_consumed字段）
    if hasattr(user, 'total_consumed'):
        user.total_consumed = new_total
        await user.save()
    
    # 确定目标升级等级
    membership_levels = await MembershipLevel.all().order_by('level')
    target_level = None
    for level in membership_levels:
        if new_total >= float(level.upgrade_amount) and level.level > current_level:
            target_level = level
    
    # 执行升级
    upgrade_message = ""
    if target_level:
        user.membership_level = target_level
        upgrade_message = f"，会员等级已升级为{target_level.name}"
        await user.save()
    
    logger.info(f"用户 {username} 消费 {request.amount} 元{upgrade_message}")
    
    return {
        "success": True,
        "message": f"消费成功{upgrade_message}",
        "data": {
            "consumed_amount": request.amount,
            "current_level": user.membership_level.name if user.membership_level else "普通",
            "total_consumption": new_total
        }
    }